package org.egedede.processmanager.ui;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.AbstractAction;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import org.egedede.processmanager.ProcessDefinition;
import org.egedede.processmanager.ProcessManager;
import org.egedede.processmanager.events.ProcessEvent;
import org.egedede.processmanager.events.ProcessListener;
import org.egedede.processmanager.logs.ProcessLogEvent;
import org.egedede.processmanager.logs.ProcessLogListener;

public class ProcessManagerPanel extends JPanel implements ProcessListener, ListSelectionListener, ProcessLogListener,
		MouseListener {

	private final ProcessManager manager;
	private final JList processes;
	private final JTextArea logs = new JTextArea();
	private ProcessDefinition selected = null;

	public ProcessManagerPanel(ProcessManager manager) {
		super();
		this.manager = manager;
		this.processes = new JList(new ProcessManagerListModel(this.manager));
		this.processes.setCellRenderer(new ProcessManagerCellRenderer());
		this.processes.addListSelectionListener(this);
		this.processes.addMouseListener(this);

		this.manager.addListener(this);
		this.initGraphics();
	}

	private void initGraphics() {
		this.setLayout(new BorderLayout());
		this.add(new JSplitPane(JSplitPane.VERTICAL_SPLIT, new JScrollPane(this.processes), new JScrollPane(this.logs)));
	}

	@Override
	public void processChanged(ProcessEvent e) {
		this.processes.repaint();
	}

	@Override
	public void valueChanged(ListSelectionEvent e) {
		ProcessDefinition process = (ProcessDefinition) this.processes.getSelectedValue();
		if (!process.equals(this.selected)) {
			if (this.selected != null) {
				this.selected.getLog().removeListener(this);
			}
			this.selected = process;
			this.logs.setText(this.selected.getCommand() + "\n");
			this.logs.append(this.selected.getLog().toString());
			this.selected.getLog().addListener(this);
		}

	}

	@Override
	public void logUpdated(final ProcessLogEvent event) {
		SwingUtilities.invokeLater(new Runnable() {
			@Override
			public void run() {
				ProcessManagerPanel.this.logs.append("\n" + event.getEntry());
			}
		});
	}

	@Override
	public void mouseEntered(MouseEvent me) {
	}

	@Override
	public void mouseExited(MouseEvent me) {
	}

	@Override
	public void mousePressed(MouseEvent me) {
		this.maybeShowPopup(me);
	}

	@Override
	public void mouseReleased(MouseEvent me) {
		this.maybeShowPopup(me);
	}

	private void maybeShowPopup(MouseEvent e) {
		final Object o = this.processes.getSelectedValue();
		if (e.isPopupTrigger()) {
			JPopupMenu menu = new JPopupMenu();
			menu.add(new AbstractAction("ClearAll") {
				@Override
				public void actionPerformed(ActionEvent ae) {
					ProcessManagerPanel.this.manager.clear();
					ProcessManagerPanel.this.processes.repaint();
				}
			});
			menu.add(new AbstractAction("DeleteSelected") {
				@Override
				public void actionPerformed(ActionEvent ae) {
					ProcessManagerPanel.this.manager.delete((ProcessDefinition) o);
					ProcessManagerPanel.this.processes.repaint();
				}
			});
			menu.add(new AbstractAction("KillSelected") {
				@Override
				public void actionPerformed(ActionEvent ae) {
					ProcessManagerPanel.this.manager.cancel((ProcessDefinition) o);
					ProcessManagerPanel.this.processes.repaint();
				}
			});
			menu.show(e.getComponent(), e.getX(), e.getY());
		}
	}

	@Override
	public void mouseClicked(MouseEvent me) {
		this.maybeShowPopup(me);
	}
}
